/**
 * NaturalNotation.java
 * 
 * Copyright (C) 2012 - Thibault BUREL
 * 
 * This file is part of MathDraft.
 *
 * MathDraft is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * MathDraft is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with MathDraft.  If not, see <http://www.gnu.org/licenses/>
 *  
 */
package drk.mathdraft.proposition.builder;

import java.util.*;

import drk.mathdraft.proposition.*;
import drk.mathdraft.proposition.Number;

public class NaturalNotation
{
	/*************************************************************************
	 *                          M E M B E R S                                *
	 *************************************************************************/	
	
	/*************************************************************************
	 *                          M E T H O D S                                *
	 *************************************************************************/
	private static Proposition analyze(Iterator<String> itr) throws SyntaxException
	{
		Stack<BinaryOperation> ops  = new Stack<BinaryOperation>();
		Stack<Proposition>     args = new Stack<Proposition>();
		
		boolean endSubExpReached = false;
		while(itr.hasNext() && !endSubExpReached)
		{
			String currentToken = itr.next();

			if (currentToken.equals("("))
			{
				args.add(analyze(itr));
			}
			else if (currentToken.equals(")"))
			{
				endSubExpReached = true;
			}
			else if (currentToken.equals("=") ||
				     currentToken.equals("+") ||
				     currentToken.equals("-") ||
				     currentToken.equals("*") ||
				     currentToken.equals("/"))
			{
				System.out.println("yop");
				analyzeBinaryOperation(currentToken, ops, args);
			}
			else if (isNumber(currentToken))
			{
				args.add(new Number(currentToken));
			}
			else if (isVariable(currentToken))
			{
				args.add(new Variable(currentToken));
			}
			else
			{
				throw new SyntaxException ("Syntax error" + currentToken);
			}
		}
		
		while(!ops.empty())
		{
			BinaryOperation last = ops.pop();
			
			if (args.size() > 1)
			{
				last.setSecond(args.pop());
				last.setFirst(args.pop());
				args.add(last);
			}
			else
			{
				throw new SyntaxException ("Syntax error");
			}
		}
		
		if (args.size() != 1)
		{
			throw new SyntaxException ("Syntax error");
		}
		return args.pop();
	}
	
	private static void analyzeBinaryOperation
		(String currentToken,
		 Stack<BinaryOperation> operators,
		 Stack<Proposition>     arguments)
	{
		BinaryOperation o;
		
		if (currentToken.equals("="))
		{
			o = new Equality();
		}
		else if (currentToken.equals("+"))
		{
			o = new Plus();
		}
		else if (currentToken.equals("-"))
		{
			o = new Minus();
		}
		else if (currentToken.equals("*"))
		{
			o = new Multiplication();
		}
		else // Division
		{
			o = new Division();
		}
		
		if(!operators.empty())
		{
			if(o.getPriority() <= operators.peek().getPriority())
			{
				BinaryOperation last = operators.pop();
				last.setSecond(arguments.pop());
				last.setFirst(arguments.pop());
				arguments.add(last);

			}
		}
		operators.add(o);
	}
	
	public static Proposition fromNaturalNotation(String s) throws SyntaxException
	{
		ArrayList<String> tokens = Scanner.tokenize(s);
		
		return analyze (tokens.iterator());
	}
	
	private static boolean isNumber (String s)
	{
		// Regexp double : [-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?
		return s.matches("[0-9]*");
	}
	
	private static boolean isVariable (String s)
	{
		return s.matches("[a-zA-Z][a-zA-Z0-9]*");
	}
}